/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = frssl_config.c                                     */
/*  NOTE      =                                                    */
/*  DATE      = 2015/07/16 by guojq                                */
/*******************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>

#include "frcomm.h"
#include "frame_cfg.h"
#include "frsutl.h"
#include "frmem.h"
#include "frlog.h"
#include "frxml_parse.h"
#include "frcmd_server.h"
#include "frssl_config.h"
#include "frssl_crypto.h"

#define FRCMD_DOS2UNIX    "dos2unix"
#define DSSL_DOMAIN       "domain:"

FR_STATIC Frlist_header *g_p_st_ssl_info = NULL;
FR_STATIC unsigned long g_ul_ssl_version = 1;
FR_STATIC pthread_rwlock_t g_ssl_rwlock;

FR_STATIC Frlist_header g_lst_ssl_info;

FR_STATIC void __send_reload_signal(void);

unsigned long frssl_config_version(void)
{
    return g_ul_ssl_version;
}

FR_STATIC void __frssl_version_set(void)
{
    g_ul_ssl_version++;
    __send_reload_signal();
}

void frssl_read_lock(void)
{
    pthread_rwlock_rdlock(&g_ssl_rwlock);
}

void frssl_read_unlock(void)
{
    pthread_rwlock_unlock(&g_ssl_rwlock);
}

/*******************************************************************************
*  FUNC     :  释放链表节点
*  ARGS     :  Frlist_node* node   需要释放的链表节点
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
FR_STATIC void __ssl_info_node_free(Frlist_node* node)
{
    FRSSL_info *p_st_info = NULL;

    if (node == NULL || node->data == NULL)
        return;
    p_st_info = (FRSSL_info *)node->data;
    
    if (p_st_info->p_file)
        frfree(p_st_info->p_file);
    if (p_st_info->p_passwd)
        frfree(p_st_info->p_passwd);
    if (p_st_info->p_domain)
        frfree(p_st_info->p_domain);
    frfree(p_st_info);
    return;
}

FR_STATIC void __ssl_info_free(FRSSL_info **pp_ssl_info)
{
    FRSSL_info *p_ssl_info = NULL;
    if (pp_ssl_info && *pp_ssl_info)
    {
        p_ssl_info = *pp_ssl_info;
        if (p_ssl_info->p_file)
            frfree(p_ssl_info->p_file);
        if (p_ssl_info->p_passwd)
            frfree(p_ssl_info->p_passwd);
        if (p_ssl_info->p_domain)
            frfree(p_ssl_info->p_domain);
        frfree(p_ssl_info);
        *pp_ssl_info = NULL;
    }
}

/*******************************************************************************
*  FUNC     :  释放链表节点
*  ARGS     :  Frlist_node* node   需要释放的链表节点
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
FR_STATIC void __ssl_node_free(Frlist_node* node)
{
    FRSSL_info *p_st_ssl = NULL;

    if (node == NULL || node->data == NULL)
        return;
    p_st_ssl = (FRSSL_info *)node->data;
    
    __ssl_info_free(&p_st_ssl);
    
    return;
}


FR_STATIC int __ssl_find_node(Frlist_node* node, const void *p_compare_data)
{
    FRSSL_info *p_st_new = NULL;
    FRSSL_info *p_st_node_ssl = NULL;

    if (node == NULL || p_compare_data == NULL || node->data == NULL)
        return 1;

    p_st_node_ssl = (FRSSL_info *)node->data;
    p_st_new = (FRSSL_info *)p_compare_data;
    
    if (p_st_node_ssl->ui_ip != p_st_new->ui_ip)
        return 1;
    
    if (p_st_node_ssl->us_port != p_st_new->us_port)
        return 1;

    if (p_st_node_ssl->p_domain && p_st_new->p_domain)
    {
        if (strcmp(p_st_node_ssl->p_domain, p_st_new->p_domain))
            return 1;
    }

    return 0;
}

/*******************************************************************************
*  FUNC     :  给ssl解码程序发送reload信号
*  ARGS     :
*  RTN      :  FR_SUCC
*              FR_FAIL
*  NOTE     :
*******************************************************************************/
FR_STATIC void __send_reload_signal(void)
{
    FILE *fp = NULL;
    char arr_oneline[10] = {0};
    int i_pid = 0;

    fp = fopen(DSSL_PID_FILE, "r");
    if (fp)
    {
        if (fgets(arr_oneline, 10, fp))
        {
            i_pid = atoi(arr_oneline);
            kill(i_pid, SIGUSR1);
        }
        fclose(fp);
    }
    return;
}

/*******************************************************************************
*  FUNC     :  查找目标ip是否在链表中
*  ARGS     :  p_st_head            链表头
*           :  ui_ip                ip地址
*           :  us_port              端口
*  RTN      :  FR_SUCC              在链表中
*              FR_FAIL              不在链表中
*  NOTE     :  
*******************************************************************************/
FR_STATIC Frlist_node *__frssl_find(Frlist_header *p_st_head, u_int ui_ip, u_short us_port, const char *p_domain)
{
    Frlist_node *p_st_find = NULL;
    FRSSL_info st_ssl_cache;
    
    memset(&st_ssl_cache, 0x00, sizeof(FRSSL_info));
    st_ssl_cache.ui_ip = ui_ip;
    st_ssl_cache.us_port = us_port;
    st_ssl_cache.p_domain = frstrdup(p_domain);
    
    p_st_find = frlist_find(p_st_head, (void *)&st_ssl_cache, __ssl_find_node);
    if (p_st_find == NULL)
    {
        frfree(st_ssl_cache.p_domain);
        return NULL;
    }
    frfree(st_ssl_cache.p_domain);

    return p_st_find;
}

FR_STATIC int __frssl_make_sslinfo(FRSSL_info *p_ssl_info, char *p_out, int i_out)
{
    char *p_encode_passwd = NULL;

    if (p_ssl_info == NULL || p_ssl_info->p_file == NULL || p_out == NULL || i_out == 0)
        return FR_FAIL;

    //ssl密码加密
    if (p_ssl_info->p_passwd && p_ssl_info->p_passwd[0] != '\0')
    {
        if (ssl_config_encrypt(p_ssl_info->p_passwd, &p_encode_passwd) != FR_SUCC)
            return FR_FAIL;

        if (p_ssl_info->p_domain && p_ssl_info->p_domain[0] != '\0')
            snprintf(p_out, i_out, "%s %d %s %s domain:%s"
                   , int_ntoa(p_ssl_info->ui_ip), p_ssl_info->us_port
                   , p_ssl_info->p_file, p_encode_passwd, p_ssl_info->p_domain);
        else
            snprintf(p_out, i_out, "%s %d %s %s"
                   , int_ntoa(p_ssl_info->ui_ip), p_ssl_info->us_port
                   , p_ssl_info->p_file, p_encode_passwd);

        frfree(p_encode_passwd);
    }
    else
    {
        if (p_ssl_info->p_domain && p_ssl_info->p_domain[0] != '\0')
            snprintf(p_out, i_out, "%s %d %s domain:%s"
                   , int_ntoa(p_ssl_info->ui_ip), p_ssl_info->us_port
                   , p_ssl_info->p_file, p_ssl_info->p_domain);
        else
            snprintf(p_out, i_out, "%s %d %s"
                   , int_ntoa(p_ssl_info->ui_ip), p_ssl_info->us_port
                   , p_ssl_info->p_file);
    }
    return FR_SUCC;
}

FR_STATIC int __frssl_xml_add(FRSSL_info *p_ssl_info)
{
    int i_ret = 0;
    char arr_value[512];
    
    if (p_ssl_info == NULL || p_ssl_info->p_file == NULL)
        return FR_FAIL;
    
    if (__frssl_make_sslinfo(p_ssl_info, arr_value, sizeof(arr_value)) != FR_SUCC)
        return FR_FAIL;
    
    i_ret = frxml_insert2doc_content(APM_CFG_FILENAME_SSL, APM_CFG_SSL_XPATH_DSSL, APM_CFG_SSL_KEY_RULE, arr_value);
    
    return i_ret;
}

FR_STATIC int __frssl_xml_update(FRSSL_info *p_ssl_info_old, FRSSL_info *p_ssl_info_new)
{
    int i_ret = 0;
    char arr_value[512];
    
    if (p_ssl_info_old == NULL || p_ssl_info_old->p_file == NULL
      || p_ssl_info_new == NULL || p_ssl_info_new->p_file == NULL)
        return FR_FAIL;

    if (__frssl_make_sslinfo(p_ssl_info_old, arr_value, sizeof(arr_value)) != FR_SUCC)
        return FR_FAIL;

    //删除老的内容
    frxml_del2doc_one_cont(APM_CFG_FILENAME_SSL, APM_CFG_SSL_XPATH_DSSL, APM_CFG_SSL_KEY_RULE, arr_value);

    if (__frssl_make_sslinfo(p_ssl_info_new, arr_value, sizeof(arr_value)) != FR_SUCC)
        return FR_FAIL;

    //添加新的内容
    i_ret = frxml_insert2doc_content(APM_CFG_FILENAME_SSL, APM_CFG_SSL_XPATH_DSSL, APM_CFG_SSL_KEY_RULE, arr_value);
    
    return i_ret;
}

/*******************************************************************************
*  FUNC     :  把ssl的内容写到内存中并保存到文件中
*  ARGS     :  ui_ip                ip地址
*           :  us_port              端口
*           :  p_passwd            password
*  RTN      :  FR_SUCC              
*              FR_FAIL              
*  NOTE     :  
*******************************************************************************/
FR_STATIC int __frssl_config_add(u_int ui_ip, u_short us_port
                    , const char *p_file_ssl, const char *p_passwd, const char *p_domain)
{
    FRSSL_info *p_ssl_node = NULL;
    Frlist_node *p_st_find = NULL;
    Frlist_node *p_st_new = NULL;
    char arr_cmd[128];

    if (p_file_ssl == NULL)
        return FR_FAIL;

    snprintf(arr_cmd, sizeof(arr_cmd), "%s %s", FRCMD_DOS2UNIX, p_file_ssl);
    system(arr_cmd);

    p_st_find = __frssl_find(g_p_st_ssl_info, ui_ip, us_port, p_domain);
    if (p_st_find && p_st_find->data)
    {
        FRSSL_info *p_ssl_info_old;
        FRSSL_info st_ssl_info_new;
        
        p_ssl_info_old = (FRSSL_info *)p_st_find->data;

        //存在该ip的节点
        //更新ssl的内容到缓存节点
        st_ssl_info_new.ui_ip = ui_ip;
        st_ssl_info_new.us_port = us_port;
        if (p_passwd)
            st_ssl_info_new.p_passwd = frstrdup(p_passwd);
        else
            st_ssl_info_new.p_passwd = NULL;
        
        if (p_file_ssl)
            st_ssl_info_new.p_file = frstrdup(p_file_ssl);
        else
            st_ssl_info_new.p_file = NULL;

        if (p_domain)
            st_ssl_info_new.p_domain = frstrdup(p_domain);
        else
            st_ssl_info_new.p_domain = NULL;

        //更新xml文件
        __frssl_xml_update(p_ssl_info_old, &st_ssl_info_new);

        if (p_ssl_info_old->p_passwd)
            frfree(p_ssl_info_old->p_passwd);
        if (p_ssl_info_old->p_file)
            frfree(p_ssl_info_old->p_file);
        if (p_ssl_info_old->p_domain)
            frfree(p_ssl_info_old->p_domain);
        p_ssl_info_old->p_passwd = st_ssl_info_new.p_passwd;
        p_ssl_info_old->p_file = st_ssl_info_new.p_file;
        p_ssl_info_old->p_domain = st_ssl_info_new.p_domain;
        
        return FR_SUCC;
    }
    p_ssl_node = (FRSSL_info *)frmalloc(sizeof(FRSSL_info));
    if (p_ssl_node == NULL)
        return FR_FAIL;

    memset(p_ssl_node, 0x00, sizeof(FRSSL_info));
    p_ssl_node->ui_ip = ui_ip;
    p_ssl_node->us_port = us_port;
    p_ssl_node->p_passwd = frstrdup(p_passwd);
    p_ssl_node->p_file = frstrdup(p_file_ssl);
    if (p_domain)
        p_ssl_node->p_domain = frstrdup(p_domain);

    //更新ssl的内容到xml
    if (__frssl_xml_add(p_ssl_node) != FR_SUCC)
    {
        if (p_ssl_node->p_passwd)
            frfree(p_ssl_node->p_passwd);
        if (p_ssl_node->p_file)
            frfree(p_ssl_node->p_file);
        if (p_ssl_node->p_domain)
            frfree(p_ssl_node->p_domain);
        frfree(p_ssl_node);
        return FR_FAIL;
    }

    p_st_new = frlist_node_create(p_ssl_node);
    if (p_st_new == NULL)
    {
        if (p_ssl_node->p_passwd)
            frfree(p_ssl_node->p_passwd);
        if (p_ssl_node->p_file)
            frfree(p_ssl_node->p_file);
        if (p_ssl_node->p_domain)
            frfree(p_ssl_node->p_domain);
        frfree(p_ssl_node);
        return FR_FAIL;
    }

    frlist_add_tail(g_p_st_ssl_info, p_st_new);
    
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  删除内存中和文件里的ssl信息
*  ARGS     :  ui_ip                ip地址
*           :  us_port              端口
*  RTN      :  FR_SUCC              
*              FR_FAIL              
*  NOTE     :  
*******************************************************************************/
FR_STATIC int __frssl_config_del(u_int ui_ip, u_short us_port, const char *p_domain)
{
    FRSSL_info *p_ssl_node = NULL;
    Frlist_node *p_st_find = NULL;

    p_st_find = __frssl_find(g_p_st_ssl_info, ui_ip, us_port, p_domain);
    if (p_st_find && p_st_find->data)
    {
        char arr_value[512];
        char arr_cmd[512];

        p_ssl_node = (FRSSL_info *)p_st_find->data;

        if (__frssl_make_sslinfo(p_ssl_node, arr_value, sizeof(arr_value)) == FR_SUCC)
        {
            frxml_del2doc_one_cont(APM_CFG_FILENAME_SSL, APM_CFG_SSL_XPATH_DSSL, APM_CFG_SSL_KEY_RULE, arr_value);
            snprintf(arr_cmd, sizeof(arr_cmd), "rm -rf %s", p_ssl_node->p_file);
            system(arr_cmd);
        }
        frlist_node_free(g_p_st_ssl_info, p_st_find, FR_YES, __ssl_node_free);
        
        return FR_SUCC;
    }
    
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  解析ssl一行的数据
*              格式：IP 端口 路径 密码
*                例：172.16.0.31 443 test 123456
*  ARGS     :  p_line                   一行xml数据
*           :  pp_ssl_info              ssl信息的结构体
*  RTN      :  FR_SUCC
*              FR_FAIL
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frssl_analyse_xml(char *p_line, FRSSL_info **pp_ssl_info)
{
    FRSSL_info *p_ssl_info = NULL;
    char *p_tmp = NULL, *p_end = NULL;
    char *p_file = NULL, *p_passwd = NULL, *p_passwd_decode = NULL;
    char *p_domain = NULL;
    u_int ui_ip = 0;
    u_short us_port = 0;

    if (p_line == NULL)
        return FR_FAIL;

    p_tmp = strchr(p_line, ' ');
    if (p_tmp == NULL)
        return FR_FAIL;
    //取得ip
    ui_ip = iptools_parse_ipaddr(p_line);

    p_tmp++;
    //取得端口
    us_port = atoi(p_tmp);

    p_tmp = strchr(p_tmp, ' ');
    if (p_tmp == NULL)
        return FR_FAIL;
    p_tmp++;

    //取得文件名
    p_end = strchr(p_tmp, ' ');
    if (p_end == NULL)
    {
        p_file = frstrdup(p_tmp);
        goto end;
    }

    p_file = (char *)frmalloc(p_end - p_tmp + 1);
    if (p_end == NULL)
        return FR_FAIL;
    snprintf(p_file, p_end - p_tmp + 1, "%s", p_tmp);

    p_tmp = p_end + 1;

    //尝试查找domain
    if (*p_tmp != '\0')
    {
        if (strncasecmp(p_tmp, DSSL_DOMAIN, strlen(DSSL_DOMAIN)) == 0)
        {
            p_domain = frstrdup(p_tmp + strlen(DSSL_DOMAIN));
            if (p_domain == NULL)
                goto err;
            goto end;
        }
        //查看是否还存在域名
        p_end = strchr(p_tmp, ' ');
        if (p_end)
        {
            //取得密钥
            int i_passwd_len = p_end - p_tmp;
            if (i_passwd_len)
            {
                p_passwd = (char *)frmalloc(i_passwd_len + 1);
                if (p_passwd == NULL)
                    goto err;
                strncpy(p_passwd, p_tmp, i_passwd_len);
                p_passwd[i_passwd_len] = '\0';
            }
            //取得域名
            if (strncasecmp(p_end + 1, DSSL_DOMAIN, strlen(DSSL_DOMAIN)) == 0)
            {
                p_domain = frstrdup(p_end + 1 + strlen(DSSL_DOMAIN));
                if (p_domain == NULL)
                    goto err;
            }
        }
        else
        {
            //取得密钥，密钥可以为空
            p_passwd = frstrdup(p_tmp);
            if (p_passwd == NULL)
            {
                frfree(p_file);
                return FR_FAIL;
            }
        }
    }

    //密钥为加密字段，做解密后存储起来
    if (p_passwd)
    {
        //把ssl的密码解密
        if (ssl_config_decrypt(p_passwd, &p_passwd_decode) != FR_SUCC)
        {
            frfree(p_file);
            frfree(p_passwd);
            return FR_FAIL;
        }
        frfree(p_passwd);
    }

end:
    p_ssl_info = (FRSSL_info *)frmalloc(sizeof(FRSSL_info));
    if (p_ssl_info == NULL)
    {
        frfree(p_file);
        frfree(p_passwd);
        return FR_FAIL;
    }
    memset(p_ssl_info, 0x00, sizeof(FRSSL_info));
    p_ssl_info->ui_ip = ui_ip;
    p_ssl_info->us_port = us_port;
    p_ssl_info->p_file = p_file;
    p_ssl_info->p_passwd = p_passwd_decode;
    p_ssl_info->p_domain = p_domain;

    *pp_ssl_info = p_ssl_info;

    return FR_SUCC;
err:
    if (p_file)
        frfree(p_file);
    if (p_domain)
        frfree(p_domain);
    if (p_passwd)
        frfree(p_passwd);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  加载ssl配置到内存
*  ARGS     :  
*  RTN      :  FR_SUCC
*              FR_FAIL
*  NOTE     :
*******************************************************************************/
int frssl_config_load(void)
{
    Frlist_header *p_xml_head = NULL;
    Frlist_node *p_st_node = NULL;
    Frvar_field *p_st_field_tmp = NULL;

    if (frxml_get_string_list(APM_CFG_FILENAME_SSL, APM_CFG_SSL_XPATH_DSSL, APM_CFG_SSL_KEY_RULE, &p_xml_head) == FR_FAIL)
    {
        FRLOG_ERROR_DETAIL("file [%s] error", APM_CFG_FILENAME_SSL);
        return FR_FAIL;
    }

    p_st_node = FRLIST_FIRST_NODE(p_xml_head);
    while(p_st_node)
    {
        p_st_field_tmp = (Frvar_field *)FRLIST_GET_NODE_DATA(p_st_node);
        if (p_st_field_tmp)
        {
            FRSSL_info *p_ssl_info = NULL;
            Frlist_node *p_st_new = NULL;

            //解析一行数据取得ssl对应文件名
            if (__frssl_analyse_xml(p_st_field_tmp->field_value.p_value, &p_ssl_info) != FR_SUCC)
                goto err;

            //添加到链表中
            p_st_new = frlist_node_create(p_ssl_info);
            if (p_st_new == NULL)
            {
                __ssl_info_free(&p_ssl_info);
                goto err;
            }

            pthread_rwlock_wrlock(&g_ssl_rwlock);
            frlist_add_tail(g_p_st_ssl_info, p_st_new);
            pthread_rwlock_unlock(&g_ssl_rwlock);
        }
        p_st_node = FRLIST_NEXT_NODE(p_st_node);
    }
    frxml_free_list(&p_xml_head);
    return FR_SUCC;
err:
    frxml_free_list(&p_xml_head);
    return FR_FAIL;
}

FR_STATIC int __ssl_config_check_node(Frlist_node* node, const void *p_compare_data)
{
    FRSSL_info *p_st_new = NULL;
    FRSSL_info *p_st_node_ssl = NULL;

    if (node == NULL || p_compare_data == NULL || node->data == NULL)
        return 1;

    p_st_node_ssl = (FRSSL_info *)node->data;
    p_st_new = (FRSSL_info *)p_compare_data;
    
    if (p_st_node_ssl->ui_ip != p_st_new->ui_ip)
        return 1;
    
    if (p_st_new->us_port != p_st_node_ssl->us_port)
        return 1;
    
    return 0;
}
/*******************************************************************************
*  FUNC     :  查询ssl信息
*  ARGS     :  
*  RTN      :  成功:FRSSL_info*; 失败:NULL
*  NOTE     :  需要外面调用frssl_read_lock加锁和frssl_read_unlock解锁
*           :  pp_ssl外面使用完不需要释放内存
*******************************************************************************/
FRSSL_info* frssl_config_lookup(u_int ui_ip, u_short us_port)
{
    FRSSL_info st_input_info;
    FRSSL_info *p_ssl_out = NULL;
    Frlist_node *p_st_find = NULL;
    
    if (ui_ip == 0)
        return NULL;
    
    memset(&st_input_info, 0x00, sizeof(FRSSL_info));
    st_input_info.ui_ip = ui_ip;
    st_input_info.us_port = us_port;
    
    p_st_find = frlist_find(g_p_st_ssl_info, (void *)&st_input_info, __ssl_config_check_node);
    if (p_st_find == NULL)
        return NULL;
    
    p_ssl_out = (FRSSL_info *)p_st_find->data;
    return p_ssl_out;
}

int frssl_config_add(u_int ui_ip, u_short us_port
                , const char *p_file_ssl, const char *p_ssl_cert_content
                , const char *p_passwd, const char *p_domain, char **pp_result)
{
    Frlist_node *p_st_new = NULL;
    FRSSL_info *p_st_info_tmp;
    
    if ((p_file_ssl == NULL || *p_file_ssl == '\0') && (p_ssl_cert_content == NULL || *p_ssl_cert_content == '\0'))
    {
        FRLOG_ERROR_DETAIL("cert and cert_content is null");
        return FR_FAIL;
    }
    if (p_file_ssl && *p_file_ssl != '\0')
        FRLOG_INFO("SSL CONFIG ADD file=[%s]", p_file_ssl);
    if (p_ssl_cert_content && *p_ssl_cert_content != '\0')
        FRLOG_INFO("SSL CONFIG ADD content=[%s]", p_ssl_cert_content);
    
    p_st_info_tmp = (FRSSL_info *)frmalloc(sizeof(FRSSL_info));
    if (p_st_info_tmp == NULL)
    {
        *pp_result = frstrdup(ERR_MALLOC_FAILED);
        FRLOG_ERROR_DETAIL("malloc failed");
        return FR_FAIL;
    }
        
    memset(p_st_info_tmp, 0x00, sizeof(FRSSL_info));
    p_st_info_tmp->i_action = SSL_ACTION_ADD;
    p_st_info_tmp->ui_ip = ui_ip;
    p_st_info_tmp->us_port = us_port;
    //证书路径，直接使用证书路径
    if (p_file_ssl && *p_file_ssl != '\0')
        p_st_info_tmp->p_file = frstrdup(p_file_ssl);
    //证书内容，证书内容存到文件中
    else if (p_ssl_cert_content && *p_ssl_cert_content != '\0')
    {
        FILE *fp = NULL;
        char arr_uuid[APM_UUID_SIZE];
        char arr_dir[512];
        char arr_cmd[512];
        char arr_ssl_file[512];

        if (fruuid(arr_uuid) != FR_SUCC)
        {
            frfree(p_st_info_tmp);
            *pp_result = frstrdup(ERR_SERIOUS_DESTROY);
            FRLOG_ERROR_DETAIL("get uuid failed");
            return FR_FAIL;
        }
        snprintf(arr_dir, sizeof(arr_dir), "%s/%s", APM_SSL_WORK_DIR, arr_uuid);

        snprintf(arr_cmd, sizeof(arr_cmd), "mkdir -p %s", arr_dir);
        system(arr_cmd);

        snprintf(arr_ssl_file, sizeof(arr_ssl_file), "%s/server.key", arr_dir);
        fp = fopen(arr_ssl_file, "w");
        if (fp == NULL)
        {
            frfree(p_st_info_tmp);
            *pp_result = frstrdup(ERR_SERIOUS_DESTROY);
            FRLOG_ERROR_DETAIL("fopen %s failed", arr_ssl_file);
            return FR_FAIL;
        }
        fwrite(p_ssl_cert_content, strlen(p_ssl_cert_content), 1, fp);

        fclose(fp);
        p_st_info_tmp->p_file = frstrdup(arr_ssl_file);
    }

    if (p_passwd)
        p_st_info_tmp->p_passwd = frstrdup(p_passwd);

    if (p_domain)
        p_st_info_tmp->p_domain = frstrdup(p_domain);

    pthread_rwlock_wrlock(&g_ssl_rwlock);
    
    p_st_new = frlist_node_create(p_st_info_tmp);
    if (p_st_new == NULL)
    {
        if (p_st_info_tmp->p_file)
            frfree(p_st_info_tmp->p_file);
        if (p_st_info_tmp->p_passwd)
            frfree(p_st_info_tmp->p_passwd);
        pthread_rwlock_unlock(&g_ssl_rwlock);
        *pp_result = frstrdup(ERR_MALLOC_FAILED);
        FRLOG_ERROR_DETAIL("malloc failed");
        return FR_FAIL;
    }
    frlist_add_tail(&g_lst_ssl_info, p_st_new);
    
    pthread_rwlock_unlock(&g_ssl_rwlock);
    
    return FR_SUCC;
}

int frssl_config_del(u_int ui_ip, u_short us_port, const char *p_domain, char **pp_result)
{
    Frlist_node *p_st_new = NULL;
    FRSSL_info *p_st_info_tmp;
    
    p_st_info_tmp = (FRSSL_info *) frmalloc(sizeof(FRSSL_info));
    if (p_st_info_tmp == NULL)
    {
        *pp_result = frstrdup(ERR_MALLOC_FAILED);
        return FR_FAIL;
    }
        
    memset(p_st_info_tmp, 0x00, sizeof(FRSSL_info));
    p_st_info_tmp->i_action = SSL_ACTION_DEL;
    p_st_info_tmp->ui_ip = ui_ip;
    p_st_info_tmp->us_port = us_port;
    p_st_info_tmp->p_domain = frstrdup(p_domain);
    
    pthread_rwlock_wrlock(&g_ssl_rwlock);
    
    p_st_new = frlist_node_create(p_st_info_tmp);
    if (p_st_new == NULL)
    {
        pthread_rwlock_unlock(&g_ssl_rwlock);
        *pp_result = frstrdup(ERR_MALLOC_FAILED);
        return FR_FAIL;
    }
    frlist_add_tail(&g_lst_ssl_info, p_st_new);
    
    pthread_rwlock_unlock(&g_ssl_rwlock);
    
    return FR_SUCC;
}

int do_ssl_commit(char **pp_result)
{
    Frlist_node *p_st_tmp = NULL;
    FRSSL_info *p_st_info_tmp = NULL;
    char arr_result[512];

    pthread_rwlock_wrlock(&g_ssl_rwlock);
    
    if (frlist_size(&g_lst_ssl_info) == 0)
    {
        pthread_rwlock_unlock(&g_ssl_rwlock);
        return FR_SUCC;
    }
    
    p_st_tmp = FRLIST_FIRST_NODE(&g_lst_ssl_info);
    while(p_st_tmp)
    {
        p_st_info_tmp = (FRSSL_info*)FRLIST_GET_NODE_DATA(p_st_tmp);
        if (p_st_info_tmp)
        {
            if (p_st_info_tmp->i_action == SSL_ACTION_ADD)
            {
                if (__frssl_config_add(p_st_info_tmp->ui_ip
                            , p_st_info_tmp->us_port, p_st_info_tmp->p_file
                            , p_st_info_tmp->p_passwd, p_st_info_tmp->p_domain) != FR_SUCC)
                {
                    snprintf(arr_result, sizeof(arr_result)
                           , "ssl config add err, [ip=%s, port=%d, file=%s]"
                           , int_ntoa(p_st_info_tmp->ui_ip), p_st_info_tmp->us_port
                           , p_st_info_tmp->p_file);
                    *pp_result = frstrdup(arr_result);
                    goto err;
                }
            }
            else if (p_st_info_tmp->i_action == SSL_ACTION_DEL)
            {
                if (__frssl_config_del(p_st_info_tmp->ui_ip, p_st_info_tmp->us_port, p_st_info_tmp->p_domain) != FR_SUCC)
                {
                    snprintf(arr_result, sizeof(arr_result)
                           , "ssl config del err, [ip=%s, port=%d]"
                           , int_ntoa(p_st_info_tmp->ui_ip), p_st_info_tmp->us_port);
                    *pp_result = frstrdup(arr_result);
                    goto err;
                }
            }
        }
        p_st_tmp = FRLIST_NEXT_NODE(p_st_tmp);
    }
    frlist_remove_all(&g_lst_ssl_info, __ssl_info_node_free);
    
    __frssl_version_set();
    
    pthread_rwlock_unlock(&g_ssl_rwlock);
    return FR_SUCC;
err:
    frlist_remove_all(&g_lst_ssl_info, __ssl_info_node_free);
    //出错删除所有的apm
    frxml_del2doc_all_cont(APM_CFG_FILENAME_SSL, APM_CFG_SSL_XPATH_DSSL, APM_CFG_SSL_KEY_RULE);
    __frssl_version_set();
    pthread_rwlock_unlock(&g_ssl_rwlock);
    return FR_FAIL;
}

int do_ssl_rollback(void)
{
    pthread_rwlock_wrlock(&g_ssl_rwlock);
    frlist_remove_all(&g_lst_ssl_info, __ssl_info_node_free);
    pthread_rwlock_unlock(&g_ssl_rwlock);
    return FR_SUCC;
}

int do_ssl_clear_all(char **pp_result)
{
    pthread_rwlock_wrlock(&g_ssl_rwlock);
    frlist_remove_all(&g_lst_ssl_info, __ssl_info_node_free);

    if (frxml_del2doc_all_cont(APM_CFG_FILENAME_SSL, APM_CFG_SSL_XPATH_DSSL, APM_CFG_SSL_KEY_RULE) != FR_SUCC)
    {
        *pp_result = frstrdup(ERR_XML_DEL_ALL);
        return FR_FAIL;
    }
    __frssl_version_set();
    pthread_rwlock_unlock(&g_ssl_rwlock);

    FRLOG_INFO_DETAIL("ssl clear all");
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  初始化ssl配置信息
*  ARGS     :  
*  RTN      :  FR_SUCC
*              FR_FAIL
*  NOTE     :
*******************************************************************************/
int frssl_config_init(void)
{
    if (pthread_rwlock_init(&g_ssl_rwlock, NULL) != 0)
    {
        FRLOG_ERROR_DETAIL("pthread_rwlock_init failed");
        return FR_FAIL;
    }

    g_p_st_ssl_info = frlist_create();
    if (g_p_st_ssl_info == NULL)
    {
        pthread_rwlock_destroy(&g_ssl_rwlock);
        FRLOG_ERROR_DETAIL("frlist create failed");
        return FR_FAIL;
    }
    frlist_header_init(&g_lst_ssl_info);

    return FR_SUCC;
}

void frssl_config_destroy(void)
{
    pthread_rwlock_destroy(&g_ssl_rwlock);
    frlist_remove_all(&g_lst_ssl_info, __ssl_info_node_free);
    frlist_destroy(g_p_st_ssl_info, __ssl_node_free);
}
